package com.agg.core.service;

import cn.hutool.core.util.ReflectUtil;
import com.agg.core.base.VoidEnum;
import com.agg.core.base.dao.IBaseMapper;
import com.agg.core.base.dto.EntityDTO;
import com.agg.core.base.dto.ExtDTO;
import com.agg.core.base.dto.PaginationDTO;
import com.agg.core.base.po.BasePO;
import com.agg.core.exception.DomainException;
import com.agg.core.utils.Beans;
import com.agg.core.utils.ObjectCopys;
import com.agg.domain.command.QueryPageCmd;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.apache.ibatis.session.SqlSession;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.agg.domain.repository.EntityMybatisRepository;

public class BaseServiceImpl<M extends IBaseMapper<T>, T extends BasePO> extends ServiceImpl<M, T> implements BaseService<T>{

    @Resource
    private EntityMybatisRepository repository;

    private M iBaseMapper;


    @Resource
    private SqlSession session;


    public void setIBaseMapper(IBaseMapper iBaseMapper) {
        this.iBaseMapper=(M)iBaseMapper;
    }

    public M getIBaseMapper() {
        return iBaseMapper;
    }
    @Override
    public <K, E,Ex> Page<T> getByPage(PaginationDTO<K, E,Ex> pagination) {
        try {
            Integer pageSize=pagination.getSize();
            Integer pageNum=pagination.getCurrent();
            Method[] methods= this.baseMapper.getClass().getMethods();
            Page page=null;
            for(Method m:methods){
                if(m.getName().equals("getByPage")){
                    K condition=pagination.getCondition();
                    Ex ot=pagination.getOther();
                    if(condition==null){
                         throw  new DomainException("查询对象不能为空");
                    }
                    if(ot==null){
                        ot=(Ex)new ExtDTO();
                    }
                    page=(Page) m.invoke(this.baseMapper,
                            new Page(pageNum,pageSize),
                            condition,
                            pagination.getOther());
                    break;
                }
            }
          /**  Method method= this.baseMapper.getClass()
                    .getDeclaredMethod("getByPage",
                            Page.class,
                            pagination.getCondition().getClass());
             method.invoke(this.baseMapper,new Page(pageNum,pageSize));**/
            return page;
        }catch (IllegalAccessException e) {
            e.printStackTrace();
            throw  new DomainException("操作失败");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            throw  new DomainException("操作失败");
        }catch (Exception e){
            e.printStackTrace();
            throw  new DomainException("操作失败");
        }

    }

    @Override
    public <K, E, Ex> Class<PaginationDTO<K, E, Ex>> getClz() {

        Class<PaginationDTO<K, E, Ex>> entitiClass = null;
        Type genericSuperclass = null;
        if (genericSuperclass instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
                    .getActualTypeArguments();
            if (actualTypeArguments != null && actualTypeArguments.length > 0) {
                entitiClass = ( Class<PaginationDTO<K, E, Ex>>) actualTypeArguments[0];
            }
        }

        return entitiClass;
    }


    @Override
    public <T extends BasePO> Page<T> loadPage(PaginationDTO<T, VoidEnum, ExtDTO> pagination) {
        T entity= pagination.getCondition();
        ExtDTO extDTO=pagination.getOther();
        //对象中字符串属性去空格
        ObjectCopys.objectToTrim(entity,true);

        M mapper=this.getIBaseMapper();
        if(mapper==null){
            Type sType = getClass().getGenericSuperclass();
            Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
            Class<M> mTClass = (Class<M>) (generics[0]);
            mapper=  session.getMapper(mTClass);
        }
        QueryPageCmd<T> pageCmd=new QueryPageCmd<T>(mapper);
        pageCmd.setPagination(pagination);
        pageCmd.setEmid(pagination.getEmid());
        Page<T> page= this.repository.loadPage(pageCmd);
        return  page;

    }
    public static Class<?>  getClazz(Object proxy){

        /**
         * 判断传入对象是否为代理对象，如果是代理对象，则根据不同的代理方式获取被代理类的类型
         */
        Class<?> clazz = proxy.getClass();
        try {
            if (AopUtils.isCglibProxy(proxy)){
                Field h = clazz.getDeclaredField("CGLIB$CALLBACK_0");
                h.setAccessible(true);
                Object dynamicAdvisedInterceptor = h.get(proxy);
                Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
                advised.setAccessible(true);
                Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
                clazz = target.getClass();
            }
            if (AopUtils.isJdkDynamicProxy(proxy)){
                Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
                h.setAccessible(true);
                AopProxy aopProxy = (AopProxy) h.get(proxy);
                Field advised = aopProxy.getClass().getDeclaredField("advised");
                advised.setAccessible(true);
                Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
                clazz = target.getClass();
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }


    @Override
    public <E> Integer saveEntity(EntityDTO<E> dto) {
        M mapper=this.getIBaseMapper();
        if(mapper==null){
            Type sType = getClass().getGenericSuperclass();
            Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
            Class<M> mTClass = (Class<M>) (generics[0]);
            mapper=  session.getMapper(mTClass);
            System.out.println("emid===="+dto.getEmid()+"|name====="+mTClass.getName());
            dto.setMapper(mapper);
        }

        return  this.repository.save(dto);
    }
}
